/*
 * PhotonRTOS础光实时操作系统 -- 多核
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Zicheng Hu <huzicheng@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <autosar/internal.h>

/**
 * 默认是已经启动了一个核，也就是MASTER核。记录通过StartCore启动的核。
 */
VAR(uint32, OS_VAR_INIT) autosar_activeated_cores;

/**
 * 记录通过StartNonAutosarCore启动的核。
 */
VAR(uint32, OS_VAR_INIT) non_autosar_activeated_cores;

/**
 * 核状态
 */
VAR(CoreStatueType, OS_VAR_INIT) autosar_core_status[MAX_CPUS];

/**
 * 核上已经调用了StartOS的核心
 */
VAR(cpumask_t, OS_VAR_INIT) autosar_startos_core;

/**
 * IDLE模式
 */
static VAR(IdleModeType, OS_VAR_INIT) autosar_idle_mode[MAX_CPUS];

/**
 * app mode
 */
static VAR(AppModeType, OS_VAR_INIT) autosar_app_mode[MAX_CPUS];

FUNC(void, OS_CODE) autosar_multicore_preinit(void)
{
	VAR(int32_t, AUTOMATIC) i;

	for (i = 0; i < MAX_CPUS; i++) {
		/**
		 * 预先初始化核状态
		 */
		if (i == OS_CORE_ID_MASTER) {
			autosar_core_status[i] = AUTOSAR_CORE;
		} else {
			autosar_core_status[i] = UNKNOWN_CORE;
		}

		/**
		 * 初始化IDLE模式
		 */
		autosar_idle_mode[i] = IDLE_NO_HALT;

		autosar_app_mode[i] = DONOTCARE;

		/**
		 * 预先初始化核启动标志
		 */
		cpumask_clear_cpu(i, &autosar_startos_core);
	}

	non_autosar_activeated_cores = 0;
	/**
	 * 默认激活了一个MASTER核
	 */
	autosar_activeated_cores = 1;
}

FUNC(void, OS_CODE) autosar_set_idle_mode(VAR(CoreIdType, AUTOMATIC) CoreID,
	VAR(IdleModeType, AUTOMATIC) IdleMode)
{
	autosar_idle_mode[CoreID] = IdleMode;
}

FUNC(IdleModeType, OS_CODE) autosar_get_idle_mode(VAR(CoreIdType, AUTOMATIC) CoreID)
{
	return autosar_idle_mode[CoreID];
}

FUNC(void, OS_CODE) autosar_set_app_mode(VAR(CoreIdType, AUTOMATIC) CoreID,
	VAR(AppModeType, AUTOMATIC) AppMode)
{
	autosar_app_mode[CoreID] = AppMode;
}

FUNC(AppModeType, OS_CODE) autosar_get_app_mode(VAR(CoreIdType, AUTOMATIC) CoreID)
{
	return autosar_app_mode[CoreID];
}

FUNC(CoreStatueType, OS_CODE) autosar_get_core_status(VAR(CoreIdType, AUTOMATIC) CoreID)
{
	if (CoreID >= MAX_CPUS) {
		return UNKNOWN_CORE;
	}

	return autosar_core_status[CoreID];
}

FUNC(CoreIdType, OS_CODE) autosar_get_core_id(void)
{
	return smp_processor_id();
}

FUNC(void, OS_CODE) autosar_start_core(VAR(CoreIdType, AUTOMATIC) CoreID)
{
	pr_debug("launch autosar core:%d\n", CoreID);
	if (autosar_activeated_cores < OsNumberOfCores) {
		autosar_activeated_cores++;
		autosar_core_status[CoreID] = AUTOSAR_CORE;
		cpu_launch(CoreID);
	}
}

FUNC(void, OS_CODE) non_autosar_start_core(VAR(CoreIdType, AUTOMATIC) CoreID)
{
	pr_debug("launch none-autosar core:%d\n", CoreID);
	if (non_autosar_activeated_cores < OsNumberOfNonAutosarCores) {
		non_autosar_activeated_cores++;
		autosar_core_status[CoreID] = NONE_AUTOSAR_CORE;
		cpu_launch(CoreID);
	}
}

FUNC(void, OS_CODE) autosar_sync_all_cores(
	P2VAR(uintptr_t, AUTOMATIC, OS_APPL_DATA) wait_data,
	VAR(int32_t,AUTOMATIC) cores)
{
	VAR(int32_t, AUTOMATIC) core_id;
	VAR(uintptr_t, AUTOMATIC) except_mask;

	core_id = autosar_get_core_id();

	except_mask = (1U << cores) - 1;

	atomic_set_bit(core_id, wait_data);

	while ((*wait_data & except_mask) != except_mask)
		mb();
}

FUNC(void, OS_CODE) autosar_shutdown_os(VAR(StatusType, AUTOMATIC) Error)
{
	VAR(SpinlockIdType, AUTOMATIC) SpinlockId;
	VAR(CoreIdType, AUTOMATIC) core_id = GetCoreID();

	/**
	 * [SWS_Os_00620] ⌈ ShutdownOS 将释放所有被调用核心占用的自旋锁。 ⌋ ( SRS_Os_80021 )
	 */
	for (SpinlockId = 0; SpinlockId < AUTOSAR_NR_SPIN_LOCK; SpinlockId++) {
		if (autosar_spin_locks[SpinlockId].owner_core_id == core_id) {
			autosar_spin_locks[SpinlockId].owner_core_id = MAX_CPUS;
			smp_unlock(&autosar_spin_locks[SpinlockId].smp_lock);
		}
	}

	/**
	 * [SWS_Os_00071] ⌈如果配置了 PostTaskHook() ，如果调用了 ShutdownOS() ，操作
	 *      系统模块将不会调用钩子。 ⌋ ( )
	 */


	/**
	 * [SWS_Os_00112] ⌈如果为 OSApplication <App>配置了特定于应用程序的关闭钩子
	 * ，
	 *      则操作系统模块应在操作系统关闭时调用 ShutdownHook_<App> 。 ⌋ ( )
	 */
#if defined(CONFIG_AUTOSAR_APPLICATION_HOOK_SHUTDOWN)
	CONTEXT_MARK_START(ENV_SHUTDOWN_HOOK)
	os_app_shutdown_hooks();
	CONTEXT_MARK_END
#endif

	/**
	 * [SWS_Os_00588] ⌈应在所有核心上调用全局 ShutdownHook。⌋ ( SRS_Os_80007 )
	 */
#if defined(CONFIG_OSEK_HOOK_SHUTDOWN)
	CONTEXT_MARK_START(ENV_SHUTDOWN_HOOK)
	ShutdownHook(Error);
	CONTEXT_MARK_END
#endif

	/**
	 * [SWS_Os_00425] ⌈如果 ShutdownOS()被调用并且 ShutdownHook() 返回则操作系
	 *      统模块将禁用所有中断并进入无限循环。 ⌋ ( )
	 */
	disable_irq();
	while (1) {
	}
}

FUNC(CoreIdType, OS_CODE) GetCoreID(void)
{
	return autosar_get_core_id();
}

FUNC(uint32, OS_CODE) GetNumberOfActivatedCores(void)
{
	/**
	 * [SWS_Os_00673] GetNumberOfActivatedCores的返回值应
	 *      小于或等于“ OsNumberOfCores ”的配置值。
	 * [SWS_Os_00626] 实现应提供GetNumberOfActivatedCores函数，
	 *      该函数返回运行 AUTOSAR 操作系统的核心数。
	 */
	return autosar_activeated_cores;
}

/**
 * [SWS_Os_00681] ⌈如果在 StartCore()期间发生错误，则不会调用ErrorHook()；
 */
FUNC(void, OS_CODE) StartCore(VAR(CoreIdType, AUTOMATIC) CoreID,
	P2VAR(StatusType, AUTOMATIC, OS_APPL_DATA) Status)
{
	VAR(StatusType, AUTOMATIC) ret = E_OK;

	if (CoreID >= OS_CORE_ID_NR) {
			ret = E_OS_ID;
	} else {
		if (autosar_get_core_status(CoreID) != UNKNOWN_CORE) {
			/**
			 * [SWS_Os_00679] 如果参数CoreIDs引用了一个已经由函数StartCore启动的核心，
			 *      则忽略相关的核心并返回
			 *  E_OS_STATE。
			 * [SWS_Os_00680] 如果参数CoreID引用了一个已经由函数
			 * StartNonAutosarCore启动的核心，
			 *      则忽略相关核心并返回 E_OS_STATE。
			 */
			ret = E_OS_STATE;
		} else if (cpumask_test_cpu(CoreID, &autosar_startos_core)) {
			/**
			 * [SWS_Os_00606] AUTOSAR 规范不支持在核心上调用StartOS后激活 AUTOSAR 核心。
			 *      如果在StartOS之后调用StartCore ，它将返回扩展状态
			 * 的E_OS_ACCESS 。 ⌋
			 * [SWS_Os_00678] 在 StartOS() 之后调用StartCore函数应返回
			 *      E_OS_ACCESS，并且不应启动核心。
			 */
			ret = E_OS_ACCESS;
		} else if (CoreID != OS_CORE_ID_MASTER) {
			/**
			 * [SWS_Os_00677] StartCore 函数将启动一个在
			 *      AUTOSAR OS 控制下运行的核心。
			 */
			autosar_start_core(CoreID);
		}
	}

	if (Status) {
		*Status = ret;
	}
}

FUNC(void, OS_CODE) StartNonAutosarCore(VAR(CoreIdType, AUTOMATIC) CoreID,
	P2VAR(StatusType, AUTOMATIC, OS_APPL_DATA) Status)
{
	VAR(StatusType, AUTOMATIC) ret = E_OK;

	if (CoreID >= OS_CORE_ID_NR) {
		/**
		 * [SWS_Os_00685] ⌈如果参数CoreID引用了一个未知的核心函数，
		 *      则StartNonAutosarCore无效并将“状态”设置为
		 *  E_OS_ID。
		 */
		ret = E_OS_ID;
	} else {
		/**
		 * [SWS_Os_00684] ⌈如果参数CoreID引用了一个已经由函数StartNonAutosarCore启动的
		 *      核心，则将“Status”设置为 E_OS_STATE。
		 */
		if (autosar_get_core_status(CoreID) != UNKNOWN_CORE) {
			ret = E_OS_STATE;
		} else if (CoreID != OS_CORE_ID_MASTER) {
			/**
			 * [SWS_Os_00683] ⌈ StartNonAutosarCore函数将启动一个不受
			 * AUTOSAR OS控制的核心。
			 */
			non_autosar_start_core(CoreID);
		}
	}

	if (Status) {
		*Status = ret;
	}
}

FUNC(void, OS_CODE) autosar_shutdown_core(void)
{
	static VAR(uintptr_t, AUTOMATIC) wait_data;

	/**
	 * [SWS_Os_00587] ⌈在调用全局 ShutdownHook 之前，所有核心都应该同步。 ⌋
	 *      ( SRS_Os_80007 )
	 */
	autosar_sync_all_cores(&wait_data, AUTOSAR_CORES);

	autosar_shutdown_os(E_OK);
}

FUNC(void, OS_CODE) ShutdownAllCores(VAR(StatusType, AUTOMATIC) Error)
{
	/**
	 * TODO： 检查是否为可信代码调用
	 * [SWS_Os_00716] ⌈如果 ShutdownAllCores 是从非可信代码调用的，则该调用将
	 * 被忽略。 ⌋
	 *      ( SRS_Os_80007 )
	 */

#if AUTOSAR_CORES > 1
	VAR(int32_t, AUTOMATIC) i;
	VAR(cpumask_t, AUTOMATIC) ipi_mask;
	/**
	 * [SWS_Os_00714] ⌈应由 API 函数 ShutdownAllCores 触发同步关机。 ⌋ ( SRS_Os_80007 )
	 */

	/* 触发多核关机IPI事件 */
	for (i = 0; i < MAX_CPUS; i++)
		cpumask_clear_cpu(i, &ipi_mask);

	/* 只给autosar核心发送关机命令 */
	for (i = 0; i < AUTOSAR_CORES; i++) {
		if (autosar_get_core_status((CoreIdType)i) == AUTOSAR_CORE) {
			cpumask_set_cpu(i, &ipi_mask);
		}
	}

	/* 给所有核心发送IPI中断，架构必须实现该功能才能完成真正的关机 */
	arch_raise_ipi(&ipi_mask, IPI_SHUTDOWN);

	/**
	 * [SWS_Os_00715] ⌈ ShutdownAllCores 不得返回。 ⌋ ( SRS_Os_80007 )
	 * 本函数永不退出，等待核上收到关机IPI事件
	 */
	while (1)
		;
#else
	autosar_shutdown_os(Error);
#endif
}

FUNC(StatusType, OS_CODE) ControlIdle(VAR(CoreIdType, AUTOMATIC) CoreID,
	VAR(IdleModeType, AUTOMATIC) IdleMode)
{
	CONTEXT_CHECK(ENV_TASK | ENV_CAT2_ISR)
#if defined(EXTENDED_STATUS)
	/**
	 * [SWS_Os_00771] 如果参数CoreID或IdleMode无效（例如引用的核心不存在；空闲模式未知），
	 *      函数ControlIdle应返回E_OS_ID 。在单核系统中，CoreID 的检查将被省略
	 * 。
	 */
	if (CoreID >= MAX_CPUS || IdleMode != IDLE_NO_HALT) {
		return E_OS_ID;
	}
#endif

	/**
	 * [SWS_Os_00802] 如果核心（由CoreID给出）已经处于另一个空闲模式（与给定的 IdleMode 不同），
	 *      则新的IdleMode将在下一次核心进入空闲模式时生效。
	 */
	autosar_set_idle_mode(CoreID, IdleMode);

	/**
	 * [SWS_Os_00770] 如果未检测到错误且参数有效，则ControlIdle函数应返回E_OK
	 */
	return E_OK;
}
